package it.uniroma2.art.owlart.protegeimpl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import it.uniroma2.art.owlart.model.ARTLiteral;
import it.uniroma2.art.owlart.model.ARTNode;
import it.uniroma2.art.owlart.model.ARTResource;
import it.uniroma2.art.owlart.model.ARTStatement;
import it.uniroma2.art.owlart.model.ARTURIResource;
import it.uniroma2.art.owlart.model.NodeFilters;
import it.uniroma2.art.owlart.protegeimpl.model.ARTLiteralProtegeImpl;
import it.uniroma2.art.owlart.protegeimpl.model.ARTNodeProtegeImpl;
import it.uniroma2.art.owlart.protegeimpl.model.ARTResourceProtegeImpl;
import it.uniroma2.art.owlart.protegeimpl.model.ARTStatementProtegeImpl;
import it.uniroma2.art.owlart.protegeimpl.model.ARTURIResourceEmptyImpl;
import it.uniroma2.art.owlart.protegeimpl.model.ARTURIResourceProtegeImpl;
import it.uniroma2.art.owlart.protegeimpl.models.BaseRDFModelProtegeImpl;
import edu.stanford.smi.protegex.owl.model.OWLModel;
import edu.stanford.smi.protegex.owl.model.OWLNamedClass;
import edu.stanford.smi.protegex.owl.model.RDFObject;
import edu.stanford.smi.protegex.owl.model.RDFProperty;
import edu.stanford.smi.protegex.owl.model.RDFResource;
import edu.stanford.smi.protegex.owl.model.RDFSDatatype;
import edu.stanford.smi.protegex.owl.model.RDFSLiteral;
import edu.stanford.smi.protegex.owl.model.triplestore.Triple;

/**
 * this factory allows to create and get Protege resources from/to ART Resources
 * <p>
 * Note that, due to strong differences between Protege way of handling triples (which is strongly driven by
 * Protege original frame-based nature) and that of other traditional triple stores, we had to implement two
 * ARTNode(Resource,URIResource) implementations. One is an empty node implementation, which is used by the
 * {@link BaseRDFModelProtegeImpl#createURIResource(String)} to create placeholders (filled only with their
 * URI) which are then really mapped to Protege implementations of ART nodes when they are added to the
 * owlModel as part of triples
 * </p>
 * 
 * @author Armando Stellato
 * 
 */
public class Protege2ARTResourceFactory {

	protected static Logger logger = LoggerFactory.getLogger(Protege2ARTResourceFactory.class);
	
	static public Triple aRTStatement2ProtegeTriple(ARTStatement artStat) {
		if (artStat == null)
			return null;
		return ((ARTStatementProtegeImpl) artStat).getProtegeTriple();
	}

	static public ARTStatement protegeTriple2ARTStatement(Triple stat) {
		if (stat == null)
			return null;
		return new ARTStatementProtegeImpl(stat);
	}

	static public RDFResource aRTResource2ProtegeResource(ARTResource sTres, OWLModel owlModel) {
		if (sTres == NodeFilters.ANY)
			return null;
		if (sTres instanceof ARTURIResourceEmptyImpl) {
			String uri = ((ARTURIResourceEmptyImpl) sTres).getURI();
			String resName = owlModel.getResourceNameForURI(uri);
			RDFResource rdfRes = owlModel.getRDFResource(resName);
			logger.trace("fino a qui rdfRes="+rdfRes);
			// maybe one of these tests is worthless, but I prefer to maintain both of them, since inner
			// behavior of Protege triple store is still not clear
			if (rdfRes == null) {
				rdfRes = owlModel.getRDFResource(uri);
				logger.trace("poi fino a qui rdfRes="+rdfRes);
				if (rdfRes == null) {					
					rdfRes = owlModel.createRDFUntypedResource(uri);
					logger.trace("infine fino a qui rdfRes="+rdfRes);
				}
			}
			logger.trace("rdfRes definita: "+rdfRes);
			return rdfRes;
		} else
			return ((ARTResourceProtegeImpl) sTres).getProtegeRDFResource();
	}

	/**
	 * the particular implementation of this method (see source) is due to the fact that the method
	 * {@link RDFResource#as(Class)} invoked as asClass(RDFProperty.class) does not work properly (in fact it
	 * is marked as experimental in Protege API doc)
	 * 
	 * @param sTres
	 * @param owlModel
	 * @return
	 */
	static public RDFProperty aRTURIResource2ProtegeProperty(ARTURIResource sTres, OWLModel owlModel) {
		if (sTres == NodeFilters.ANY)
			return null;
		// return (RDFProperty)((ARTResourceProtegeImpl)sTres).getProtegeRDFResource().as(RDFProperty.class);
		// return (RDFProperty)((ARTURIResourceProtegeImpl)sTres).getProtegeRDFResource();
		String resName = owlModel.getResourceNameForURI(sTres.getURI());
		RDFProperty prop = owlModel.getRDFProperty(resName);
		if (prop == null)
			prop = owlModel.createRDFProperty(resName);
		return prop;
	}

	/*
	 * never tested, added for compliance to OWL ART API 2.0.3 featuring typed literal creation
	 * */
	static public RDFSDatatype aRTURIResource2ProtegeRDFSDatatype(ARTURIResource sTres, OWLModel owlModel) {
		if (sTres == NodeFilters.ANY)
			return null;
		RDFSDatatype dt = owlModel.getRDFSDatatypeByURI(sTres.getURI());
		if (dt == null)
			dt = owlModel.createRDFSDatatype(owlModel.getResourceNameForURI(sTres.getURI()));
		return dt;
	}

	static public RDFObject aRTNode2ProtegeValue(ARTNode sTNode, OWLModel owlModel) {
		if (sTNode == NodeFilters.ANY)
			return null;
		if (sTNode instanceof ARTURIResourceEmptyImpl) {
			//logger.debug("method: aRTNode2ProtegeValue: " + sTNode + " is instance of ARTURIResourceEmptyImpl");
			RDFResource res = aRTResource2ProtegeResource(((ARTResource) sTNode), owlModel);
			//logger.debug("create res instead of obj: " + res);
			return res;
		} else
			return ((ARTNodeProtegeImpl) sTNode).getProtegeRDFObject();
	}

	
	static public RDFResource aRTNode2ProtegeResource(ARTNode sTNode, OWLModel owlModel) {
		if (sTNode == NodeFilters.ANY)
			return null;
		if (sTNode instanceof ARTURIResourceEmptyImpl) {
			//logger.debug("method: aRTNode2ProtegeValue: " + sTNode + " is instance of ARTURIResourceEmptyImpl");
			RDFResource res = aRTResource2ProtegeResource(((ARTResource) sTNode), owlModel);
			//logger.debug("create res instead of obj: " + res);
			return res;
		} else
			return (RDFResource)((ARTNodeProtegeImpl) sTNode).getProtegeRDFObject();
	}
	
	static public RDFResource aRTNode2ProtegeClass(ARTNode sTNode, OWLModel owlModel) {
		// return (RDFProperty)((ARTResourceProtegeImpl)sTres).getProtegeRDFResource().as(RDFProperty.class);
		// return (RDFProperty)((ARTURIResourceProtegeImpl)sTres).getProtegeRDFResource();
		String resName = owlModel.getResourceNameForURI(((ARTURIResourceEmptyImpl)sTNode).getURI());
		OWLNamedClass prop = owlModel.getOWLNamedClass(resName);
		if (prop == null)
			prop = owlModel.createOWLNamedClass(resName);
		return prop;
	}
	
	static public RDFSLiteral aRTLiteral2ProtegeLiteral(ARTLiteral stLiteral) {
		if (stLiteral == null)
			return null;
		if (stLiteral == NodeFilters.ANY)
			return null;
		else
			return ((ARTLiteralProtegeImpl) stLiteral).getLiteral();
	}

	static public ARTResource protegeResource2ARTResource(RDFResource res) {
		if (res == null)
			return NodeFilters.ANY;
		else
			return new ARTResourceProtegeImpl(res);
	}

	static public ARTURIResource protegeResource2ARTURIResource(RDFResource res) {
		if (res == null)
			return NodeFilters.ANY;
		else
			return new ARTURIResourceProtegeImpl(res);
	}

	static public ARTNode protegeRDFObject2ARTNode(RDFObject val) {
		if (val == null)
			return NodeFilters.ANY;
		else
			return new ARTNodeProtegeImpl(val);
	}

	static public ARTLiteral protegeLiteral2ARTLiteral(RDFSLiteral sesLiteral) {
		if (sesLiteral == null)
			return NodeFilters.ANY;
		else
			return new ARTLiteralProtegeImpl(sesLiteral);
	}

	/*
	 * static public ARTBNode sesameBNode2ARTBNode(BNode sesBNode) { if (sesBNode==null) return
	 * NodeFilters.ANY; else return new ARTBNodeProtegeImpl(sesBNode); }
	 */

}
